// Sage Android Client.
// Connect to a Sage server, remotely execute commands and display results.
//
// Copyright (C) 2010, Harald Schilly <harald.schilly@gmail.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

package org.sagemath.android;

import org.sagemath.android.fx.FunctionEditor;

import org.json.JSONArray;
import org.json.JSONException;

import android.content.Context;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Static global Data.
 * 
 * @author Harald Schilly
 */
final public class Global {
  private Global() {
  };
  
  private static String FN_SETTINGS = "settings.json";
  
  public static final String TAG = "SageAndroid";
  
  /**
   * ID used for the Intent to identify a {@link FunctionEditor}
   */
  public static final int FUNC_EDIT = 313245;
  
  // directional flags
  public static final int RIGHT = 1374, LEFT = 1375, FLIP = 1376;
  
  // cool number and used for zoom in and zoom out.
  public static double GOLDEN_RATIO = 1.61803399;
  
  private static CalculationAPI api;
  
  final static void setCalculationAPI(CalculationAPI api) {
    Global.api = api;
  }
  
  final public static CalculationAPI getCalculationAPI() {
    return api;
  }
  
  // Don't try to use localhost, because localhost is the Android
  // device itself. You always have to connect to some other machine.
  final static Set<Server> servers = new HashSet<Server>(3);
  
  // TODO remove initial list of servers
  static {
    servers.add(new Server("sagenb.org", "admin", "test"));
  }
  
  // private static SharedPreferences settings = null;
  
  private static Server server = null;
  
  private static SageAndroid context = null;
  
  static void setContext(SageAndroid context) {
    Global.context = context;
    try {
      loadSettings();
    } catch (IOException ex) {
      // TODO handle this
    } catch (JSONException ex) {
      // TODO handle this
    }
  }
  
  final public static Context getContext() {
    return context;
  }
  
  /**
   * writes the list of servers to a json file. for more, read {@link
   * loadSettings()}.
   */
  final static void saveSettings() {
    FileOutputStream fos = null;
    try {
      fos = context.openFileOutput(FN_SETTINGS, Context.MODE_PRIVATE);
      BufferedOutputStream bos = new BufferedOutputStream(fos);
      
      JSONArray json = new JSONArray();
      for (Server s : servers) {
        JSONArray entry = new JSONArray();
        entry.put(s.server);
        entry.put(s.username);
        entry.put(s.password);
        json.put(entry);
      }
      bos.write(json.toString().getBytes());
      bos.close();
      
    } catch (FileNotFoundException e) {
      // we just write to the fos, this should never fail, ...
    } catch (IOException ex) {
      // TODO handle this
    } finally {
      try {
        fos.close();
      } catch (IOException ex) {
      }
    }
  }
  
  private final static StringBuilder loadSb = new StringBuilder();
  
  /**
   * Reads the storead JSON data.<br>
   * Example:
   * 
   * <pre>
   * [ 
   *   [ "http://server1", "franz", "99999" ], 
   *   [ "http://server2", "susi", "secret" ] 
   * ]
   * </pre>
   * 
   * @throws IOException
   * @throws JSONException
   */
  final static void loadSettings() throws IOException, JSONException {
    // create "empty" settings file if it does not exist
    if (context.getFileStreamPath(FN_SETTINGS).exists()) {
      saveSettings();
      return;
    }
    
    // first, read the file
    FileInputStream fis = context.openFileInput(FN_SETTINGS);
    try {
      BufferedReader br = new BufferedReader(new InputStreamReader(fis));
      loadSb.setLength(0);
      for (int c; (c = br.read()) >= 0;) {
        loadSb.append(c);
      }
    } finally {
      fis.close();
    }
    
    // then assume everything is readable from the json, otherwise an exception
    // is thrown
    List<Server> tmpServers = new ArrayList<Server>();
    JSONArray json = new JSONArray(loadSb.toString());
    for (int i = json.length() - 1; i >= 0; i--) {
      JSONArray entry = json.getJSONArray(i);
      tmpServers.add(new Server(entry.getString(0), entry.getString(1), entry.getString(2)));
    }
    
    // then replace the data (updating it would be better)
    servers.clear();
    servers.addAll(tmpServers);
  }
  
  final static void setServer(Server selServer) {
    // we probably have to update an entry, remove it and ...
    for (Server s : servers) {
      if (selServer.server.equals(s.server)) {
        servers.remove(s);
      }
    }
    // ... add it
    servers.add(selServer);
    // point to the selected one
    server = selServer;
  }
  
  /**
   * @return password or if not set, ""
   */
  final static String getPassword() {
    return (server == null) ? "" : server.password;
  }
  
  /**
   * @return username or if not set, ""
   */
  final static String getUser() {
    return (server == null) ? "" : server.username;
  }
  
  /**
   * @return Server
   */
  final public static Server getServer() {
    return server;
  }
  
}
